/** @jsxImportSource @emotion/react */
import * as React from "react";
import {
    IconButton,
    IconX,
    useToast,
    InputPure,
    SuffixInput,
    Popover,
    PopoverContent,
    PopoverHeading,
    PopoverDescription,
    PopoverClose,
    Touchable,
    PopoverRefer,
    ListFlexRow,
    DdMenu,
    IconRefButton,
    IconMoreVertical,
    DdMenuItem,
    Text,
    Itext,
    IconAnchor,
    IconPlus, IconMaximize2, IconVideo, IconVideoOff, IconShoppingCart, IconScissors, IconSave, Button
} from "customize-easy-ui-component";

import {useContext} from "react";
import RoutingContext from "../routing/RoutingContext";
import {SuffixRefInput} from "customize-easy-ui-component/esm/Form";
import {eqpTypeAllMap} from "../dict/eqpComm";
import {reportStatusMap} from "../task/DeviceListItem";
import {usePipingUnitMultiSelect} from "../pipeline/hook/usePipingUnitMultiSelect";
import cutting_board_knife from "../images/cutting-board-knife.jpg";
import {RegState_Enum, UseState_Enum} from "../device/__generated__/DetailedGuideQuery.graphql";
import useSessionStorageState from 'use-session-storage-state'


export interface IdName{
    id: string,
    name: string,
}
//单元的父辈，管道装置对象模型；
export interface Pipe{
    id: string,
    //使用单位
    useu: IdName,
    //管道装置 本平台编码
    cod: string,
    //管道装置 监察编码
    oid: string,
}
/**归属检验业务   获知当前检验任务单也即管道报告目前包含那些管道单元了。 直接塞给'jiesessionStorage['管道单元过滤']
 * */
export interface DetailTaskID{
    task: string,
    detail: string,
}
/**因为 sessionStorage以及Relay共同都会用的； 类型适配器。 不是都来自Relay Query<>;
 * 简易的已经选定管道单元的列表-每个设备部分关键字段
 * */
export interface IPipingUnitEntity {
    id: string,
    //管道单元编码
    code: string,
    //监察编码
    rno: string,
    //管道名 上传国家平台
    name: string,
    //使用状态
    ust: UseState_Enum,
    reg: RegState_Enum,
    //下次检验日期1 （在线、年度）粗的检 ，
    nxtd1: string,
    //下次检验日期2 (机电定检，内检，全面）
    nxtd2: string,
    start: string,
    stop: string,
    proj: string,
    leng: number,
    //使用单位
    useu: IdName,
    //行政区划   ：类型 没有特别强制声明的。 和后端Eqp Device Equipment接口模型{ad:?}一致吗?
    // ad: any,
    //管道装置
    pipe: Pipe,
    crDate: string,
}
export type PipingUnit_KeyEnum = "code" | "rno" | "name";
/**关联对象，从大列表中选择一个对象的，可套用这个伪对话框模式。
 * */
interface Props {
    //【采信编辑结果】回调：最终修改本编辑器集合，后续可以倒腾给后端数据库的。
    onSetEqps?: (arr: Array<IPipingUnitEntity>) => void;
    //伪对话框起跳前的当前编辑器数据打包; 触发了点击，保存状态，返回后才能恢复啊。正在当前编辑器页面修改的字段都存储到history.state;
    onDialog?: () => any;
    //[目的]指引转入伪对话框跳转路由页面去做state{}数据修改==选择设置某字段。
    //表示给用户看的关键字，用户以此识别编辑器是哪一个。发起人编辑器页面也需要核对emodel后提取Ndt保存数据，以及跳转当前输入焦点到刚刚被选中的伪对话目标字段autoFocus。
    //emodel?: string | undefined;
    //当前编辑的哪一个字段： 选择关联对象后要挂接字段。以及返回页面后跳转当前输入焦点到刚刚被选中的伪对话目标字段autoFocus。
    //叶子层次的非{}内嵌对象类型的：最后不可再分的属性，基本类型字段。
    field: string;
    //history.push(,state)无法传入function()给state的；@只能变相的做法，传递数据引用的结构路径名了。
    //【对象不一定就是一层】深度复制的？ 嵌套多层次结构的复杂引用对象如何办：
    //倒数第二层的/父辈第一级的:要设置的是嵌套的第二层的对象中的字段。 比如编辑器映射字段实际是：eqp.svp.{第二层的字段}那么就应该设置p1field=“svp”;
    p1field?: string;
    //路径path+部分queryString参数; 用户选择完毕所需要的关联对象之后，点击返回URL;支持当前SPA的path路径,自带?号的;
    //reurl: string;
    autoFocus?: boolean;
    //伪对话框需要跳转去的页面URL
    // dialogUrl: string;
    //编辑器存活期的旧数据（上一次退出编辑模态后的）：devices是还未保存到后端数据库的。【可变更】最新DB数据 +relay；这个会被多选编辑器所变更的！
    devices: Array<IPipingUnitEntity>;
    //复位用的：devices还不算是真正的未修改数据，这个=最原始[]来自后端数据库的。但是也可能来自json恢复；
    orgDevs?: Array<IPipingUnitEntity>;
    //可以编辑修改的模式
    edit: boolean;
    //部分数据源属于快照历史性信息，可能并非最新后端数据的。
    jsoned?: boolean;
    //3个预设值过滤项
    //使用单位 useu{ id name crDate}
    useu?: IdName;
    //所属管道装置 pipe:.id name=cod；
    pipe?: IdName;
    //归属检验业务 3个预先可指定的关联ID； 获知当前检验任务单也即管道报告目前包含那些管道单元了。
    //来自列表过滤器组件定义的字段名,管道单元过滤.detailTid{"task":"R_OiNCAySDKVrUzRz83WiVRhc2s","detail":"taAFpS0sRqOcfrnjXBY3hERldGFpbA"}
    detailTid?: DetailTaskID;
    //选定这个单元: 所要执行的回调。
    onSelect?: (sel: IPipingUnitEntity, index:number) => void;
}
//页面和数据分离后又要被迫整合在一块了？
//非高层次通用的组件。语义整合：　数据获取和规格化显示部分组合在一个文件内。前端graphql底层缓存：不见得每次都会发送请求给后端的。
//graphQL想把多个Query同时都坐在一个Hook函数里面一次性向后端读取，有许多障碍：页面分割，公用组件嵌套，父辈组件知晓子孙辈组件数据请求和参数还得传递数据，不过前端有缓存。
/** 伪对话框的做法！ 两个独立路由页面的接力。
 初始化状态：？编辑修改模式的{...storage[]}，未进入编辑状态的@.data。 上一级组件内带状态控制：到底是不是编辑状态？
 编辑框点击进入展示全部选定设备 删除等 跳转。
 后面按钮进入跳转选择主页面，后面直接修改storage;
 交互模式合理性考虑：避免手机场景下的左右割裂，ChooseEqps组件新增加更多设备的显示？直接放在主页面也就是TwoHalf右半边页面上，从/device路由选定设备之后返回就能弹出显示。
 删除单一个选定设备，点击设备号显示多个明细字段，增加+跳转/device挑选,清空。
 非可编辑的状态下：不能删除、不能清空、不能跳转挑选。
 编辑状态 && 显示出所有已选定的设备列表对话框状态， 【选定完毕要确认?】。已被选定的设备列表：到底是那些组成：初始化还是编辑器带入。?
 伪对话框的做法！在/device路由页面点击链接会直接修改save[field],导致window.history.state?.state同步被修改了; {上级组件confirmation()}.{field就是'meqp'}修改操作History基础API。
 * 若用 history.state 有大小限制，最大只能接受 360 KB。
 * redux中的数据发生变化，相关页面（connect），会自动变化：类比像Relay store? Relay本地附加的Store直接添加附加字段，#不能增加删除新的ID对象?;
 * 用localstorage这样不可代替redux, 当两个组件共用一个数据，如果其中一个组件改变数据，希望另一个组件响应该变化时{react自动同步}，用localstorage无法做到。大量数据存储本地，可以使用indexDB本地数据库进行存储（网页游戏）。
 * 【问题】必须在父辈编辑器达到可共享，父辈其它跳转也需要保存本设备挑选组件的数组(不管有没有变更过了)，设备变更数组需要暴露到父组件编辑器大环境中。
 * Reset 和 Clear(Cancel)不同意思： Reset编辑器恢复初始选择(退出编辑，保留修改前的devs[]数据)
 */
export const ChoosePipingUnits= ({ onSetEqps, onDialog, field,p1field, jsoned, useu,pipe,detailTid,
                           autoFocus,devices,edit,orgDevs,onSelect, ...other }:Props) =>
{
    //这里【】设备对象数据实际来自父辈页面的内省传递来的，有可能并不是完整对象，不是所有字段都有数据的。
    const { history } = useContext(RoutingContext);
    const reurl= history.createHref(history.location);     //我自己现在是哪个URL,跳转伪对话框路由页面之后，还得关闭对话框=还得跳转回这个URL来啊。
    //真正的可修改编辑，光光edit还不够表达：拆解状态和功能，同时兼容代码复用。  autoFocus代表应该进入编辑模式。
    const [editing, setEditing] = React.useState(edit && autoFocus);
    // const [open, setOpen] = React.useState(false);
    //若devices是undefined:那么完全从本地sessionStorage中提取的。
    //编辑模式，非编辑仅仅查看模式？区别，到底有没有被修改了？【input点击】编辑的要初始化，非编辑模式的也要把设备丢给？还是分开走。
    //从伪对话框返回的+编辑状态的：把sessionStorage中提取传给上级组件编辑器devices状态变量。
    //？多选集自从上一次初始化以后就已经被修改了： 伪对话框返回？取消对多选集的修改的采用，单个编辑字段刷新reset命令。
    //【缺点】用useStorageState必须关闭SPA浏览器物理页才能把初始化值重置到sessionStorage，不能根据APP路由器页面切换触发自动更新，强制页面刷新Realy也都不能立刻改动dxDevs。
    //局限性：上下级组件都有useStorageState的两个无法立刻通知到位，需要刷新或路由切换，奇怪组件上下级嵌套都不能立刻确保一致性。
    // const [dxDevs, setDxDevs,] = useStorageState(
    //     sessionStorage,
    //     '管道单元多选集',
    //     devices as any[]
    // );
    console.log("ChoosePipingUnitsdatDB 初始devices",devices);
    const [dxDevs, setDxDevs, { isPersistent,removeItem  }] = useSessionStorageState('管道单元多选集', {
        defaultValue: devices as any[]
    });

    //只要有ChooseEqps组件就都会首先就修改了，#而不是延迟点：等到对话框弹出准备进入编辑状态才会修改的？【明确表示进入编辑模式的】

    React.useEffect(() => {
        //进入编辑模式，把sessionStorage切换成本编辑器的当前最新数据集
        editing && setDxDevs(devices);
    }, [editing, devices, setDxDevs]);
    //可能还没有进入编辑模式的。
    const handleDelete = React.useCallback((devArr: Array<IPipingUnitEntity>) => {
        //if(!editing)   setEditing(true);这样子会导致第一次点击设备删除按钮实际上并没有触发？和上面useEffect有矛盾，useEffect会同时的滞后再做修正导致效果丢失。
        setDxDevs(devArr);
    }, [setDxDevs]);
    const displayDevs= editing? dxDevs: devices;

    const handleReset = React.useCallback(() => {
        //【问题】给当前伪对话框的：浏览器若直接刷新，能会恢复旧的已经清空的选择数据。导致save=>devices被复原了。
        history.push(reurl, {time: Date()});        // setDxDevs([]);  没效果
        //恢复后端数据库的数据集，把本编辑框的选择清空，恢复初始数据。
        onSetEqps!(orgDevs!)
    }, [onSetEqps, orgDevs,reurl, history]);
    //只有关闭Tab浏览器重启才能清空，强制刷新URL不能清空；只有清空后进入本组件的，这里的defaultValue才会生效，removeItem清空。
    const [flt, setFlt, { isPersistent:isPersistentFlt,removeItem:removeItemFlt  }] = useSessionStorageState('管道单元过滤', {
        defaultValue: {useu, pipe, detailTid}
    });

    const inputComp=(
        <SuffixRefInput  readOnly autoFocus={autoFocus}
                         component={InputPure}
                         value={ `已选(${displayDevs?.length || '0'})条` }
                         onClick={async () => {
                             // const save=await onDialog!();     //编辑器来源，context已确定的；离开之前 需要临时保留数据。==confirmation()；
                             console.log("ChooseEqps组件传递",window.history.state?.state, "myurl=",reurl);
                             setOpen(!open);
                             //   history.push(`/device`, {save, field, reurl, p1field});
                         } }
                         {...other}
        >
            <IconButton
                variant="ghost"
                icon={<IconX />}
                label="清空所有设备"
                css={{
                    display: edit ? undefined : 'none'
                }}
                onClick={async (e) => {
                    onSetEqps!([]);
                    e.preventDefault();
                    e.stopPropagation();
                } }
            />
        </SuffixRefInput>
    );
    //只有可以编辑修改模式才能做的
    const moreBtn=(
        <>
            <IconButton  variant="ghost"  icon={<IconPlus />}  label="增加一个"
                  onClick={async (e) => {
                      setEditing(true);     //立刻就得跳转URL，多此一举=失效了？
                      setDxDevs(devices);
                      const save=await onDialog!();     //编辑器来源，context已确定的；离开之前 需要临时保留数据。==confirmation()；
                      setFlt({useu, pipe, detailTid});      //其它过滤字段直接清空掉。
                      console.log("ChooseEqps组件传递2",window.history.state?.state, "myurl=",reurl);
                      history.push(`/pipingUnit`, {save, field, reurl, p1field, multi:true});
                  } }
            />
            <IconButton  variant="ghost"  icon={editing? <IconSave /> : <IconScissors />}  label="编辑模式下删除后必须确认"
                     onClick={async (e) => {
                         //只能手动进入编辑模式editing：
                         //太别扭了： 必须在这里插入确认步骤！，否则逻辑更加混淆不堪。
                         //多个设备删除后【明确确认】因为没有从设备台账伪对话框返回的直接对话框删除设备的，必须确认状态。
                         if(editing){
                             onSetEqps!(dxDevs);            //进入只读模态
                             setEditing(false);
                         }
                         else
                             setEditing(true);       //进入修改允许模态
                     } }
            />
            <Button  variant="outline"   label="采用当前多选集"
                         disabled={devices===dxDevs}
                         onClick={async (e) => {
                             //不能加if(editing){  进入编辑模态会useEffect作用导致旧数据复制给sessionStorage;
                             onSetEqps!(dxDevs);
                         } }
            >采用</Button>
        </>
    );
    //点击删除某个设备｛申明进入了编辑修改状态｝，点击增加切换URL,【真正弹出主体】
    const {view: selectDevsDialog, open, setOpen}= usePipingUnitMultiSelect({
        dxDevs: displayDevs,
        setDxDevs: handleDelete,
        refer:inputComp,
        addBtn: edit? moreBtn: undefined,
        edit: editing,
        onReset: handleReset,
        onSelect,
    });

  return (
      <>
          {selectDevsDialog}
      </>
  );
}


/*附加3个参数注入的：
    const useu= {id: "xftDCQ76QxWsmflDeIBuVFVuaXQ", name:"漳州安然燃气有限公司云霄分公司"};
    const pipe= {id: "tH81_fRiT6yYNkPfxvAHN1BpcGVsaW5l", name: "3506D3926"};
    const detailTid= {task: "CFffYHZ8RByDQt8BW3nTplRhc2s", detail: "L1IvEmhSSzezC_Ui9nXmA0RldGFpbA"};
* */
